pub fn is_equal(a: f32, b: f32) -> bool {
    if a > b {
        return (a - b) < 0.1;
    }
    return (b - a) < 0.1;
}

fn add(a: f32, b: f32) -> Option<f32> {
    Some(a + b)
}

fn sub(a: f32, b: f32) -> Option<f32> {
    Some(a - b)
}

fn mul(a: f32, b: f32) -> Option<f32> {
    Some(a * b)
}

fn div(a: f32, b: f32) -> Option<f32> {
    if b == 0.0 {
        return None;
    }
    Some(a / b)
}

#[derive(Debug, Clone, Copy)]
pub struct ExprOp {
    pub exec: fn(f32, f32) -> Option<f32>,
    pub name: &'static str,
    pub is_primary: bool,
}

impl ExprOp {
    pub fn add() -> Self {
        Self {
            exec: add,
            name: "+",
            is_primary: false,
        }
    }

    pub fn sub() -> Self {
        Self {
            exec: sub,
            name: "-",
            is_primary: false,
        }
    }

    pub fn mul() -> Self {
        Self {
            exec: mul,
            name: "*",
            is_primary: true,
        }
    }

    pub fn div() -> Self {
        Self {
            exec: div,
            name: "/",
            is_primary: true,
        }
    }
}

#[derive(Debug, Clone, Copy)]
pub enum ExprItem {
    Num(f32),
    Op(ExprOp),
}

impl ExprItem {
    pub fn f32(v: f32) -> ExprItem {
        ExprItem::Num(v)
    }

    pub fn add() -> ExprItem {
        ExprItem::Op(ExprOp::add())
    }

    pub fn sub() -> ExprItem {
        ExprItem::Op(ExprOp::sub())
    }

    pub fn mul() -> ExprItem {
        ExprItem::Op(ExprOp::mul())
    }

    pub fn div() -> ExprItem {
        ExprItem::Op(ExprOp::div())
    }
}

fn calc_expr(left: ExprItem, op: ExprItem, right: ExprItem) -> Option<f32> {
    if let ExprItem::Num(left) = left {
        if let ExprItem::Op(op) = op {
            if let ExprItem::Num(right) = right {
                println!("计算 {}{}{}", left, op.name, right);
                return (op.exec)(left, right);
            }
        }
    }

    None
}

pub fn calc24_2(exprs: &mut Vec<ExprItem>) -> Option<f32> {
    if exprs.len() < 3 {
        if let ExprItem::Num(v) = exprs[0] {
            return Some(v);
        }
        return None;
    }

    let mut index = 1;
    while index < exprs.len() {
        if let ExprItem::Op(op) = exprs[index] {
            if op.is_primary {
                break;
            }
        }
        index += 2;
    }

    if index >= exprs.len() {
        index = 1;
    }

    let left = exprs[index - 1];
    let op = exprs[index];
    let right = exprs[index + 1];

    let result = calc_expr(left, op, right)?;
    exprs[index - 1] = ExprItem::Num(result);
    exprs.remove(index);
    exprs.remove(index);

    calc24_2(exprs)
}

// A   +    B       *       C    + D
// A   +    none    none    none + D
// A   +    BC      none    none + D
// ABC none none    none    none + D
// A

pub fn test_calc2() {
    let mut vec = Vec::new();
    vec.push(ExprItem::f32(1.0));
    vec.push(ExprItem::mul());
    vec.push(ExprItem::f32(2.0));
    vec.push(ExprItem::add());
    vec.push(ExprItem::f32(3.0));
    vec.push(ExprItem::mul());
    vec.push(ExprItem::f32(4.0));

    vec.push(ExprItem::add());

    vec.push(ExprItem::f32(1.0));
    vec.push(ExprItem::mul());
    vec.push(ExprItem::f32(2.0));
    vec.push(ExprItem::add());
    vec.push(ExprItem::f32(3.0));
    vec.push(ExprItem::mul());
    vec.push(ExprItem::f32(4.0));

    let v = calc24_2(&mut vec);
    println!("{:#?}", v);
}
